package chloroform

import _root_.util.logging.Logged
import scaladuct._

/**
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: 17.4.11
 * Time: 11:21
 * To change this template use File | Settings | File Templates.
 */

trait InjectingPage[X] extends ConfigPageDecorator[X] with Logged {
  def lookupFunction(): LookupFunctions.LookupFunction;

  override def consume(cookie: Cookie): ConfigResult[X] = {
    val lookupFn: LookupFunctions.LookupFunction = lookupFunction()

    if (cookie != Terminal && lookupFn != null) {
      val cookieBean = CookieBeanFactory(cookie)

      def filterContextReferences(prop: PropertyValue[AnyRef]): Boolean = {
        prop.refTypeInfo != null && prop.refTypeInfo.name != null &&
          prop.refTypeInfo.name != "" &&
          prop.clazz != classOf[String]
      }

      def inject(prop: PropertyValue[AnyRef]): PropertyValue[AnyRef] = {
        //val lookupFn: LookupFunctions.LookupFunction = lookupFunction()

        val resultPageFns = lookupFn(prop.refTypeInfo.name)
        if (resultPageFns.size == 1) {
          val valuePageFn = resultPageFns(0)
          //val valuePage = valuePageFn(prop.clazz)
          val valuePage = valuePageFn(prop.typeInfo.getType)
          if (valuePage.getCookie == Terminal) {
            valuePage.consume(valuePage.getCookie) match {
              case NextPage(page) => error("Consuming terminal yields another page instead of a starter")
              case NewStarter(starter) => {
                // Note: the starter should to return a context value that does not have to be explicitly destroyed.
                val value = starter.newInstance

                prop.update(value.asInstanceOf[AnyRef])
              }
            }
          } else {
            error("Referenced page " + prop.refTypeInfo.name + " is not fully preconfigured")
          }
        } else error("Lookup for '" + prop.refTypeInfo.name + "' returns " + resultPageFns.size + " results. Just one expected." )
      }

      val updatedProps = cookieBean.props.filter(filterContextReferences).map(inject)
      if (!updatedProps.isEmpty) {
        cookieBean.update(updatedProps)
      }

      super.consume(cookie)

    } else {
      if (lookupFn == null)
        warn("Lookup function is not available for injecting context values")

      super.consume(cookie)
    }

  }


}